package com.wjk.kylin.mall.common.web.interceptor;

import cn.hutool.core.util.IdUtil;
import com.wjk.kylin.mall.common.core.constant.Constants;
import com.wjk.kylin.mall.common.core.dto.base.SessionUserDTO;
import com.wjk.kylin.mall.common.web.filter.WrappedHttpServletRequest;
import com.wjk.kylin.mall.common.web.filter.WrappedHttpServletResponse;
import com.wjk.kylin.mall.common.web.util.IpUtil;
import com.wjk.kylin.mall.common.web.util.SysSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Optional;

@Slf4j
@Component
public class BaseInterceptor implements HandlerInterceptor {
    private static final ThreadLocal<Long> THREAD_LOCAL = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        super.preHandle(request, response, handler);
        //trace
        Optional.ofNullable(request.getHeader(Constants.TRACE_ID_KEY)).ifPresent(traceId -> {
            if (StringUtils.isBlank(traceId)) {
                traceId = IdUtil.simpleUUID();
                log.info("header traceId is null create new traceId:{}", traceId);
            }
            MDC.put(Constants.TRACE_ID_KEY, traceId);
            SysSession.setTraceId(traceId);
        });

        String userId = request.getHeader(Constants.USER_ID_KEY);
        String userName = request.getHeader(Constants.USER_NAME_KEY);
        String nickName = request.getHeader(Constants.NICK_NAME_KEY);
        if (StringUtils.isNotBlank(userId)) {
            SessionUserDTO dto = SessionUserDTO.builder()
                    .userId(Long.parseLong(userId))
                    .userName(userName)
                    .nickName(nickName)
                    .build();
            SysSession.setSessionUser(dto);
            log.info("请求用户信息 ====> userId:{},userName:{},nickName:{}", userId, userName, nickName);
        } else {
            log.warn("请求头中没有用户信息");
        }

        //请求开始计时，单位毫秒
        THREAD_LOCAL.set(System.currentTimeMillis());

        //请求信息
        String remoteIp = IpUtil.getRemoteIP(request);
        String uri = request.getRequestURI();
        String params = null;
        if (request instanceof WrappedHttpServletRequest) {
            try {
                params = ((WrappedHttpServletRequest) request).getRequestParams();
            } catch (IOException e) {
                log.error("打印请求参数异常", e);
                throw e;
            }
        }

        if (isExcludeUri(uri)){
            return true;
        }

        log.info("请求 ====> 接口：{}, ip：{}, 入参：{}", uri, remoteIp, params);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if (StringUtils.isNotBlank(SysSession.getTraceId())) {
            response.setHeader(Constants.TRACE_ID_KEY, SysSession.getTraceId());
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//        super.afterCompletion(request, response, handler, ex);

        //应答信息
        String uri = request.getRequestURI();

        //计算耗时,单位毫秒
        Long startTime = THREAD_LOCAL.get();
        long endTime = System.currentTimeMillis();
        long executeTime = endTime - startTime;

        if (executeTime > 10 * 1000) {
            log.warn("接口[{}]响应耗时超过10秒!", uri);
        }

        String responseParams = null;
        if (response instanceof WrappedHttpServletResponse) {
            try {
                WrappedHttpServletResponse wrappedHttpServletResponse = ((WrappedHttpServletResponse) response);
                responseParams = wrappedHttpServletResponse.getResponseParams();
                wrappedHttpServletResponse.flushToDest();
            } catch (Exception e) {
                log.error("获取应答参数异常", e);
                throw e;
            }
        }

        if (isExcludeUri(uri)){
            return;
        }

        log.info("响应 ===> 接口：{}, 耗时：{}ms, 出参：{}", uri, executeTime, responseParams);

        //
        SysSession.removeTraceId();
        SysSession.removeSessionUser();
        THREAD_LOCAL.remove();
    }

    /**
     * 被排除打印的uri
     */
    private boolean isExcludeUri(String uri) {
        return false;
    }
}
